package ccm.component.menu;

import ccm.common.*;
import ccm.communicate.common.NotStartException;
import ccm.communicate.smctp.Smctp;
import ccm.component.override.JCheckBoxMenuItem;
import ccm.component.override.JFrame;
import ccm.component.override.JMenuItem;
import ccm.component.override.VFlowLayout;

import javax.swing.*;
import java.awt.*;
import java.awt.datatransfer.StringSelection;
import java.awt.event.*;
import java.util.ArrayList;
import java.util.Arrays;

public class MenuJPanel extends JPanel implements ActionListener, ReceiveDataListener, StatusChangeListener, ComponentListener
{
    static protected final int activePageCnt=1;
    protected final JPanel pageSelectJPanel;
    protected final JPanel pageJPanel;
    protected final JPanel leftJPanel;
    protected final JFrame leftJFrame;
    protected final JScrollPane leftJScrollPane;
    protected final byte[] receiveBuf;
    protected final ArrayList<ReceiveDataListener> receiveDataListener;
    private final Component[] rightMenuComponent;
    protected String saveArgPrefix;
    protected volatile boolean start;
    protected int receiveBufStart;
    protected JCheckBoxMenuItem syncActivatePageJCheckBox;
    MenuItemJPanel[] menuItems;
    int currentPageIndex=0; //这个是从-activeCnt开始的
    int activatePageIndex=0; //这个是从-activeCnt开始的

    public MenuJPanel()
    {
        this(null);
    }

    public MenuJPanel(String saveArgPrefix)
    {
        super();
        setMinimumSize(new Dimension(100,100));
        setPreferredSize(new Dimension(100,300));
        this.saveArgPrefix=saveArgPrefix==null?"":(saveArgPrefix.endsWith("/")?saveArgPrefix:(saveArgPrefix+"/"));
        setLayout(new BorderLayout());
        start=false;
        menuItems=new MenuItemJPanel[0];
        receiveBuf=new byte[10240];
        {
            /*页面选择面板构造*/
            pageSelectJPanel=new JPanel();
            final JScrollPane jScrollPane=new JScrollPane(pageSelectJPanel);
            jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
            add(jScrollPane,BorderLayout.NORTH);
            pageSelectJPanel.setLayout(new FlowLayout(FlowLayout.LEFT));

        }
        {
            /*页面构造*/
            pageJPanel=new JPanel();
            final JScrollPane jScrollPane=new JScrollPane(pageJPanel);
            jScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            jScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER);
            add(jScrollPane,BorderLayout.CENTER);
            pageJPanel.setLayout(new GridLayout(6,0));
        }
        {
            /*左侧栏构造*/
            leftJPanel=new JPanel();
            leftJPanel.setLayout(new VFlowLayout());
            leftJScrollPane=new JScrollPane(leftJPanel);
            leftJScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
            leftJScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
            leftJScrollPane.setVisible(false);
            add(leftJScrollPane,BorderLayout.WEST);
            leftJFrame=new JFrame()
            {
                @Override
                public void restart()
                {
                }
            };
            leftJFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
            leftJFrame.addWindowListener(new WindowAdapter()
            {
                @Override
                public void windowClosing(WindowEvent e)
                {
                    leftJFrame.setVisible(false);
                    leftJFrame.remove(leftJScrollPane);
                    MenuJPanel.this.add(leftJScrollPane,BorderLayout.WEST);
                    MenuJPanel.this.revalidate();
                    MenuJPanel.this.repaint();
                }
            });
        }

        {
            rightMenuComponent=new Component[7];
            final JMenuItem copyJMenuItem=new JMenuItem("加载到输入框");
            rightMenuComponent[0]=copyJMenuItem;
            copyJMenuItem.addActionListener(e->
            {
                for(MenuItemJPanel menuItemJPanel: menuItems)
                {
                    if(menuItemJPanel instanceof ValuableMenuItem&&((menuItemJPanel.page==currentPageIndex)||((currentPageIndex<0&&menuItemJPanel.isActivate()))))
                    {
                        ((ValuableMenuItem)menuItemJPanel).loadValueToInput();
                    }
                    else if(menuItemJPanel instanceof ExRequestValueInterface&&((menuItemJPanel.page==currentPageIndex)||((currentPageIndex<0&&menuItemJPanel.isActivate()))))
                    {
                        ((ExRequestValueInterface)menuItemJPanel).loadValueToInput();
                    }
                }
            });
            final JMenuItem freshJMenuItem=new JMenuItem("刷新所有");
            rightMenuComponent[1]=freshJMenuItem;
            freshJMenuItem.addActionListener(e->
            {
                requestMaxPageIndex();
                for(int i=0;i<pageSelectJPanel.getComponentCount();++i)
                {
                    ((PageJButton)pageSelectJPanel.getComponents()[i]).setNeedRequest(true);
                }
                for(MenuItemJPanel menuItemJPanel: menuItems)
                {
                    if(menuItemJPanel!=null)
                    {
                        menuItemJPanel.needRequestValue=true;
                        menuItemJPanel.needRequest=true;
                    }
                }
            });

            final JMenuItem clearAll=new JMenuItem("清空所有");
            rightMenuComponent[2]=clearAll;
            clearAll.addActionListener(e->clear());

            final JMenuItem popJMenuItem=new JMenuItem("弹出左面板");
            rightMenuComponent[3]=popJMenuItem;
            popJMenuItem.addActionListener(e->
            {
                if(leftJPanel.getComponentCount()>0)
                {
                    MenuJPanel.this.remove(leftJScrollPane);
                    leftJFrame.add(leftJScrollPane);
                    MenuJPanel.this.revalidate();
                    MenuJPanel.this.repaint();
                    leftJFrame.revalidate();
                    leftJFrame.repaint();
                    leftJFrame.setVisible(true);
                }
            });
            syncActivatePageJCheckBox=new JCheckBoxMenuItem("双向页面同步");
            rightMenuComponent[4]=syncActivatePageJCheckBox;
            syncActivatePageJCheckBox.setSelected(CCMConfigManager.setBooleanIfAbsent(this.saveArgPrefix+"ccm/component/menu/MenuJPanel"+"/syncActivatePage",true));
            syncActivatePageJCheckBox.addActionListener(e->
            {
                requestNowPage();
                storeConfig();
            });
            final JMenuItem clipBoardJMenuItem=new JMenuItem("复制所有到剪切板");
            rightMenuComponent[5]=clipBoardJMenuItem;
            clipBoardJMenuItem.addActionListener(e->
            {
                StringBuilder stringBuilder=new StringBuilder();
                for(MenuItemJPanel menuItemJPanel: menuItems)
                {
                    if(menuItemJPanel!=null)
                    {
                        stringBuilder.append(menuItemJPanel.name).append(':').append(menuItemJPanel).append('\n');
                    }
                }
                final StringSelection data=new StringSelection(stringBuilder.toString());
                Toolkit.getDefaultToolkit().getSystemClipboard().setContents(data,data);
            });
            final JMenuItem clipBoardAllJMenuItem=new JMenuItem("复制本页到剪切板");
            rightMenuComponent[6]=clipBoardAllJMenuItem;
            clipBoardAllJMenuItem.addActionListener(e->
            {
                StringBuilder stringBuilder=new StringBuilder();
                for(MenuItemJPanel menuItemJPanel: menuItems)
                {
                    if(menuItemJPanel!=null&&((menuItemJPanel.page==currentPageIndex)||((currentPageIndex<0&&menuItemJPanel.isActivate()))))
                    {
                        stringBuilder.append(menuItemJPanel.name).append(':').append(menuItemJPanel).append('\n');
                    }
                }
                final StringSelection data=new StringSelection(stringBuilder.toString());
                Toolkit.getDefaultToolkit().getSystemClipboard().setContents(data,data);
            });
            final JPopupMenu jPopupMenu=new JPopupMenu();
            MouseAdapter mouseAdapter=new MouseAdapter()
            {
                public void mouseClicked(MouseEvent e)
                {
                    if(e.getButton()==MouseEvent.BUTTON3)
                    {
                        jPopupMenu.removeAll();
                        for(Component ri: rightMenuComponent)
                        {
                            jPopupMenu.add(ri);
                        }
                        jPopupMenu.show((Component)e.getSource(),e.getX(),e.getY());
                    }
                }
            };
            pageSelectJPanel.addMouseListener(mouseAdapter);
            pageJPanel.addMouseListener(mouseAdapter);
            leftJPanel.addMouseListener(mouseAdapter);
            this.addMouseListener(mouseAdapter);
        }

        setMaxPageIndex(0);
        loadConfig();
        (new FreshRunnable()).start();
        addComponentListener(this);
        receiveDataListener=new ArrayList<>();
    }

    protected void loadConfig()
    {
        final String prefix=saveArgPrefix+"ccm/component/menu/MenuJPanel";
        currentPageIndex=CCMConfigManager.setIntegerIfAbsent(prefix+"/currentPageIndex",0);
        syncActivatePageJCheckBox.setSelected(CCMConfigManager.setBooleanIfAbsent(prefix+"/syncActivatePage",true));
        final boolean popLeftPanel=(CCMConfigManager.setBooleanIfAbsent(prefix+"/popLeftPanel",false));
        if(popLeftPanel!=leftJFrame.getContentPane().getComponentCount()>0)
        {
            if(popLeftPanel)
            {
                MenuJPanel.this.remove(leftJScrollPane);
                leftJFrame.add(leftJScrollPane);
                MenuJPanel.this.revalidate();
                MenuJPanel.this.repaint();
                leftJFrame.revalidate();
                leftJFrame.repaint();
                leftJFrame.setVisible(true);
            }
            else
            {
                leftJFrame.setVisible(false);
                leftJFrame.remove(leftJScrollPane);
                MenuJPanel.this.add(leftJScrollPane,BorderLayout.WEST);
                MenuJPanel.this.revalidate();
                MenuJPanel.this.repaint();
            }
        }
        updateDataList();
        for(MenuItemJPanel menuItemJPanel: menuItems)
        {
            if(menuItemJPanel!=null)
            {
                menuItemJPanel.loadConfig();
            }
        }
    }

    /**
     * 设置参数保存前缀
     * 会自动刷新所有的参数
     *
     * @param saveArgPrefix 参数保存前缀
     */
    public void setSaveArgPrefix(String saveArgPrefix)
    {
        this.saveArgPrefix=saveArgPrefix==null?"":(saveArgPrefix.endsWith("/")?saveArgPrefix:(saveArgPrefix+"/"));
        for(MenuItemJPanel menuItemJPanel: menuItems)
        {
            if(menuItemJPanel!=null)
            {
                menuItemJPanel.setSaveArgPrefix(this.saveArgPrefix);
            }
        }
        loadConfig();
    }

    protected void setMaxPageIndex(int maxPageIndex)
    {
        if(maxPageIndex+activePageCnt!=pageSelectJPanel.getComponentCount())
        {
            final int oldButtonListLen=pageSelectJPanel.getComponentCount();
            //删掉多的
            for(int i=oldButtonListLen-1;i>=maxPageIndex+activePageCnt;--i)
            {
                pageSelectJPanel.remove(i);
            }
            //加入新来的
            for(int i=oldButtonListLen;i<maxPageIndex+1;++i)
            {
                PageJButton nb=new PageJButton();
                nb.addActionListener(this);
                pageSelectJPanel.add(nb);
                setPageInfo(i-activePageCnt,null);
            }
            pageSelectJPanel.revalidate();
            pageSelectJPanel.repaint();
            loadConfig();
            updateDataList();
            for(int i=activePageCnt;i<pageSelectJPanel.getComponentCount();++i)
            {
                ((PageJButton)pageSelectJPanel.getComponents()[i]).setNeedRequest(true);
            }
        }
    }

    protected void setMaxDataIndex(int maxDataIndex)
    {
        if(maxDataIndex!=menuItems.length)
        {
            MenuItemJPanel[] tmp=new MenuItemJPanel[maxDataIndex];
            for(int i=0, n=Math.min(menuItems.length,maxDataIndex);i<n;++i)
            {
                tmp[i]=menuItems[i];
            }
            for(MenuItemJPanel menuItemJPanel: tmp)
            {
                if(menuItemJPanel!=null)
                {
                    menuItemJPanel.needRequest=true;
                }
            }
            menuItems=tmp;
        }
        loadConfig();
    }

    /**
     * 设置页面信息
     *
     * @param pageIndex >=0表示正常页面，<0表示激活
     * @param name      名字
     */
    public void setPageInfo(int pageIndex,String name)
    {
        PageJButton jb=(PageJButton)pageSelectJPanel.getComponents()[pageIndex+activePageCnt];
        jb.setNeedRequest(false);
        if(pageIndex<0)
        {
            jb.setText("active");
        }
        else if(name==null)
        {
            jb.setText("P"+pageIndex);
        }
        else
        {
            jb.setText("P"+pageIndex+":"+name);
        }
        jb.revalidate();
        jb.repaint();
        pageSelectJPanel.revalidate();
        pageSelectJPanel.repaint();
    }

    /**
     * 添加一个接收数据监听器
     *
     * @param listener 监听器
     * @throws NullPointerException 监听器为null时抛出此异常
     */
    public void addReceiveDataListener(ReceiveDataListener listener)
    {
        if(listener==null)
        {
            return;
        }
        if(!receiveDataListener.contains(listener))
        {
            receiveDataListener.add(listener);
        }
    }

    @Override
    public void componentResized(ComponentEvent e)
    {
        this.updateDataList();
    }

    protected void updateDataList()
    {
        currentPageIndex=Math.max(-activePageCnt,Math.min(currentPageIndex,pageSelectJPanel.getComponentCount()-activePageCnt-1));
        updateDataList(currentPageIndex);
    }

    protected void updateDataList(int page)
    {
        storeConfig();
        page=Math.max(-activePageCnt,Math.min(page,pageSelectJPanel.getComponentCount()-activePageCnt-1));
        currentPageIndex=Math.max(-activePageCnt,Math.min(currentPageIndex,pageSelectJPanel.getComponentCount()-activePageCnt-1));
        {
            Component[] li=pageSelectJPanel.getComponents();
            for(int i=0;i<li.length;++i)
            {
                ((PageJButton)li[i]).getModel().setPressed(i==page+activePageCnt);
            }
        }
        if(page==currentPageIndex)
        {
            {
                int tmpLen=0;
                MenuItemJPanel[] tmp=new MenuItemJPanel[menuItems.length];
                for(MenuItemJPanel menuItemJPanel: menuItems)
                {
                    if(menuItemJPanel instanceof SingleMenuItem&&(menuItemJPanel.page==page||((page<0&&menuItemJPanel.isActivate()))))
                    {
                        tmp[tmpLen++]=menuItemJPanel;
                        menuItemJPanel.setActivateEnable(menuItemJPanel.page==page);
                    }
                }
                if(tmpLen>0)
                {
                    final int itemHeight=tmp[0].getPreferredSize().height;
                    final int totalHeight=pageJPanel.getHeight();
                    if(itemHeight!=0&&totalHeight!=0)
                    {
                        final int row=totalHeight/itemHeight;
                        final int col=(int)Math.ceil(1.0f*tmpLen/row);
                        GridLayout gridLayout=(GridLayout)pageJPanel.getLayout();
                        gridLayout.setRows(row);
                        gridLayout.setColumns(col);
                        //System.out.println(itemHeight+","+tmpLen+","+row+","+col+","+this.getHeight()+","+totalHeight+",");
                        boolean isSame=true;
                        for(int j=0;j<row&&isSame;++j)
                        {
                            for(int i=0;i<col&&isSame;++i)
                            {
                                int k1=i*row+j;
                                if(k1<tmpLen)
                                {
                                    int k2=j*col+i;
                                    isSame=(k2<pageJPanel.getComponentCount())&&(pageJPanel.getComponents()[k2]==tmp[k1]);
                                }
                            }
                        }
                        if(!isSame)
                        {
                            pageJPanel.removeAll();
                            for(int j=0;j<row;++j)
                            {
                                for(int i=0;i<col;++i)
                                {
                                    int k1=i*row+j;
                                    pageJPanel.add((k1<tmpLen)?tmp[k1]:new JPanel());
                                }
                            }
                            pageJPanel.revalidate();
                            pageJPanel.repaint();
                        }
                    }
                }
                else
                {
                    pageJPanel.removeAll();
                    pageJPanel.revalidate();
                    pageJPanel.repaint();
                }
            }
            {

                int tmpLen=0;
                MenuItemJPanel[] tmp=new MenuItemJPanel[menuItems.length];
                for(MenuItemJPanel menuItemJPanel: menuItems)
                {
                    if(menuItemJPanel instanceof ArrayMenuJPanel&&(menuItemJPanel.page==page||((page<0&&menuItemJPanel.isActivate()))))
                    {
                        tmp[tmpLen++]=menuItemJPanel;
                        menuItemJPanel.setActivateEnable(menuItemJPanel.page==page);
                    }
                }
                if(tmpLen>0)
                {
                    boolean isSame=tmpLen==leftJPanel.getComponentCount();
                    for(int i=0;i<tmpLen&&isSame;++i)
                    {
                        isSame=(leftJPanel.getComponents()[i]==tmp[i]);
                    }
                    if(!isSame)
                    {
                        leftJPanel.removeAll();
                        for(int i=0;i<tmpLen;++i)
                        {
                            leftJPanel.add(tmp[i]);
                        }
                        leftJScrollPane.setVisible(true);
                        leftJScrollPane.setPreferredSize(new Dimension(400,200));
                        leftJScrollPane.revalidate();
                        leftJScrollPane.repaint();
                        if(leftJFrame.getContentPane().getComponentCount()>0)
                        {
                            leftJFrame.revalidate();
                            leftJFrame.repaint();
                            leftJFrame.setVisible(true);
                        }
                        this.revalidate();
                        this.repaint();
                    }
                }
                else
                {
                    leftJPanel.removeAll();
                    leftJFrame.setVisible(false);
                    leftJScrollPane.setVisible(false);
                    leftJScrollPane.revalidate();
                    leftJScrollPane.repaint();
                    revalidate();
                    repaint();
                }
            }
        }
    }

    /**
     * 保存设置
     * 注意，不会递归保存
     */
    protected void storeConfig()
    {
        final String prefix=saveArgPrefix+"ccm/component/menu/MenuJPanel";
        {
            int tmp=CCMConfigManager.setIntegerIfAbsent(prefix+"/currentPageIndex",0);
            //确保currentPageIndex不被还没设置好的pageSelectJPanel更新
            if(tmp>=-activePageCnt&&tmp<pageSelectJPanel.getComponentCount())
            {
                CCMConfigManager.setInteger(prefix+"/currentPageIndex",currentPageIndex);
            }
            CCMConfigManager.setBoolean(prefix+"/popLeftPanel",(leftJFrame.getContentPane().getComponentCount()>0));
        }
        CCMConfigManager.setBoolean(prefix+"/syncActivatePage",syncActivatePageJCheckBox.isSelected());
    }

    @Override
    public void componentMoved(ComponentEvent e)
    {

    }

    @Override
    public void componentShown(ComponentEvent e)
    {

    }

    @Override
    public void componentHidden(ComponentEvent e)
    {

    }

    @Override
    public void actionPerformed(ActionEvent e)
    {
        if(e.getSource() instanceof PageJButton)
        {
            for(int i=0;i<pageSelectJPanel.getComponentCount();++i)
            {
                if(pageSelectJPanel.getComponents()[i].equals(e.getSource()))
                {
                    currentPageIndex=i-activePageCnt;
                    ((PageJButton)pageSelectJPanel.getComponents()[i]).setNeedRequest(true);
                    if(currentPageIndex>=0)
                    {
                        requestNowPage(currentPageIndex);
                    }
                    updateDataList();
                }
            }
        }
    }

    private void requestNowPage(int page)
    {
        if(page>=0)
        {
            activatePageIndex=page;
        }
        //System.out.println("requestNowPage"+page);
        if(syncActivatePageJCheckBox.isSelected())
        {
            int start=0;
            byte[] buf=new byte[64];
            start=Buffer.setUint8(buf,start,activatePageIndex);
            addTailAndSend(buf,start,0X1F);
        }
    }

    protected void addTailAndSend(byte[] buf,int start,int type)
    {
        if(receiveDataListener!=null&&buf!=null)
        {
            start=Buffer.setUint8(buf,start,start);
            start=Buffer.setUint16(buf,start,Crc.crc16Modbus(buf,0,start));
            buf[start]=0X13;
            buf[start+1]=0X18;
            buf[start+2]=(byte)type;
            sendData(Arrays.copyOfRange(buf,0,start+3));
        }
    }

    private void sendData(byte[] data)
    {
        if(data!=null)
        {
            final ReceiveDataEvent event=new ReceiveDataEvent(MenuJPanel.this,data);
            receiveDataListener.forEach(r->
            {
                try
                {
                    r.receiveData(event);
                }catch(Exception ex)
                {
                    ex.printStackTrace();
                }
            });
        }
    }

    private void requestNowPage()
    {
        requestNowPage(activatePageIndex);
    }

    private void requestMaxPageIndex()
    {
        System.out.println("requestMaxPageIndex(0X18)");
        int start=0;
        byte[] buf=new byte[64];
        addTailAndSend(buf,start,0X18);
    }

    private void requestPageInfo(int page)
    {
        System.out.println("requestPageInfo(0X1A) "+page);
        int start=0;
        byte[] buf=new byte[64];
        start=Buffer.setUint8(buf,start,page);
        addTailAndSend(buf,start,0X1A);
    }

    private void requestData(int dataIndex)
    {
        System.out.println("requestData(0X1C) "+dataIndex);
        int start=0;
        byte[] buf=new byte[64];
        start=Buffer.setUint16(buf,start,dataIndex);
        addTailAndSend(buf,start,0X1C);
    }


    @Override
    public void receiveData(ReceiveDataEvent event)
    {
        synchronized(receiveBuf)
        {
            try
            {
                if(!start) return;
                System.out.println("MenuJPanel receiveData");
                for(byte datum: event.getData())
                {
                    receiveBuf[receiveBufStart]=datum;
                    receiveBufStart=(receiveBufStart+1)%receiveBuf.length;
                    final int type=Buffer.getUint8(receiveBuf,receiveBufStart-1);
                    if(type>=0X17&&type<=0x24&&Buffer.getUint8(receiveBuf,receiveBufStart-3)==0X13&&Buffer.getUint8(receiveBuf,receiveBufStart-2)==0X18)
                    {
                        final int len=Buffer.getUint8(receiveBuf,receiveBufStart-6);
                        if(Buffer.getUint16(receiveBuf,receiveBufStart-5)==Crc.crc16Modbus(receiveBuf,receiveBufStart-6-len,len+1))
                        {
                            if(type==0X17&&len==4)
                            {
                                final int maxData=Buffer.getUint16(receiveBuf,receiveBufStart-6-len);
                                final int maxPage=Buffer.getUint8(receiveBuf,receiveBufStart-6-len+2);
                                final int actPage=Buffer.getUint8(receiveBuf,receiveBufStart-6-len+3);
                                setMaxPageIndex(maxPage);
                                setMaxDataIndex(maxData);
                                if(actPage<maxPage&&syncActivatePageJCheckBox.isSelected())
                                {
                                    activatePageIndex=actPage;
                                    currentPageIndex=activatePageIndex;
                                    ((PageJButton)pageSelectJPanel.getComponents()[activatePageIndex+activePageCnt]).setNeedRequest(true);
                                    updateDataList();
                                }
                                requestNowPage();
                                System.out.println("MenuJPanel receiveMaxPageIndex(0X17) maxPage="+maxPage+" maxData="+maxData);
                            }
                            else if(type==0X19)
                            {
                                final int page=Buffer.getUint8(receiveBuf,receiveBufStart-6-len);
                                final String str=Buffer.getString(receiveBuf,receiveBufStart-6-len+1,len-1,"GBK","UTF-8");
                                setPageInfo(page,str);
                                System.out.println("MenuJPanel receivePageInfo(0X19) page="+page+" str="+str);
                            }
                            else if(type==0X1B)
                            {
                                final int dataIndex=Buffer.getUint16(receiveBuf,receiveBufStart-6-len);
                                final int flags=Buffer.getUint8(receiveBuf,receiveBufStart-6-len+2);
                                final boolean canModify=(flags&(0X01))!=0;
                                final boolean isArray=(flags&(0X04))!=0;
                                final ScnsType dataType=ScnsType.valueOf(Buffer.getUint8(receiveBuf,receiveBufStart-6-len+3));
                                final int page=Buffer.getUint8(receiveBuf,receiveBufStart-6-len+4);
                                final float smallStep=Buffer.getFloat(receiveBuf,receiveBufStart-6-len+5);
                                final Pair<Object,Integer> pair=MenuItemFactory.decodeInnerDataEx(isArray,dataType,receiveBuf,receiveBufStart-6-len+9);
                                final int start=pair.getValue()-(receiveBufStart-6-len);
                                final Object ex=pair.getKey();
                                final String str=Buffer.getString(receiveBuf,receiveBufStart-6-len+start,len-start,"GBK","UTF-8");
                                System.out.println("MenuJPanel receiveData(0X1B) flags="+flags+" canModify="+canModify+" isArray="+isArray+" type="+dataType+" str="+str+" page="+page+" start="+start+" ex="+ex);
                                final Class<? extends MenuItemJPanel> aClass=MenuItemFactory.getMenuItemClass(isArray,dataType);
                                if(dataIndex<menuItems.length)
                                {
                                    if(menuItems[dataIndex]==null||!aClass.isInstance(menuItems[dataIndex])||menuItems[dataIndex].type!=dataType)
                                    {
                                        menuItems[dataIndex]=MenuItemFactory.getMenuItem(this::sendData,rightMenuComponent,saveArgPrefix,dataIndex,canModify,isArray,dataType,page,str,ex);
                                    }
                                    menuItems[dataIndex].needRequest=false;
                                    menuItems[dataIndex].needRequestValue=true;
                                    menuItems[dataIndex].setCanModify(canModify);
                                    menuItems[dataIndex].setPage(page);
                                    menuItems[dataIndex].setName(str);
                                    menuItems[dataIndex].setStep(smallStep);
                                }
                                updateDataList();

                            }
                            else if(type==0X1D)
                            {
                                final int dataIndex=Buffer.getUint16(receiveBuf,receiveBufStart-6-len);
                                final int flags=Buffer.getUint8(receiveBuf,receiveBufStart-6-len+2);
                                final boolean canModify=(flags&(0X01))!=0;
                                final boolean isArray=(flags&(0X04))!=0;
                                final ScnsType dataType=ScnsType.valueOf(Buffer.getUint8(receiveBuf,receiveBufStart-6-len+3));
                                final Class<? extends MenuItemJPanel> aClass=MenuItemFactory.getMenuItemClass(isArray,dataType);
                                if(dataIndex<menuItems.length&&menuItems[dataIndex]!=null&&aClass.isInstance(menuItems[dataIndex])&&menuItems[dataIndex].type==dataType)
                                {
                                    menuItems[dataIndex].setCanModify(canModify);
                                    if(menuItems[dataIndex] instanceof ValuableMenuItem)
                                    {
                                        ((ValuableMenuItem)menuItems[dataIndex]).decodeValueAndSet(receiveBuf,receiveBufStart-6-len+4);
                                    }
                                    menuItems[dataIndex].needRequestValue=false;
                                }
                                updateDataList();
                                System.out.println("MenuJPanel receiveValue(0X1D) canModify="+canModify+" type="+dataType);
                            }
                            else if(type==0X21)
                            {
                                try
                                {
                                    final int dataIndex=Buffer.getUint16(receiveBuf,receiveBufStart-6-len);
                                    final ScnsType dataType=ScnsType.valueOf(Buffer.getUint8(receiveBuf,receiveBufStart-6-len+2));
                                    if(menuItems[dataIndex]!=null)
                                    {
                                        if(menuItems[dataIndex].type==dataType&&menuItems[dataIndex] instanceof ExRequestDataInterface)
                                        {
                                            ((ExRequestDataInterface)menuItems[dataIndex]).decodeExAndSet(receiveBuf,receiveBufStart-6-len+3,len-3);
                                        }
                                        else
                                        {
                                            menuItems[dataIndex].needRequest=true;
                                        }
                                    }
                                }catch(Exception e)
                                {
                                    e.printStackTrace();
                                }
                            }
                            else if(type==0X23)
                            {
                                try
                                {
                                    final int dataIndex=Buffer.getUint16(receiveBuf,receiveBufStart-6-len);
                                    final ScnsType dataType=ScnsType.valueOf(Buffer.getUint8(receiveBuf,receiveBufStart-6-len+2));
                                    if(menuItems[dataIndex]!=null)
                                    {
                                        if(menuItems[dataIndex].type==dataType&&menuItems[dataIndex] instanceof ExRequestValueInterface)
                                        {
                                            ((ExRequestValueInterface)menuItems[dataIndex]).decodeExAndSet(receiveBuf,receiveBufStart-6-len+3,len-3);
                                        }
                                        else
                                        {
                                            menuItems[dataIndex].needRequest=true;
                                        }
                                    }
                                }catch(Exception e)
                                {
                                    e.printStackTrace();
                                }
                            }
                        }
                    }
                }
            }catch(Exception e)
            {
                e.printStackTrace();
            }
        }
    }

    public void clear()
    {
        final boolean start=this.start;
        this.start=false;
        menuItems=new MenuItemJPanel[0];
        receiveBufStart=0;
        Arrays.fill(receiveBuf,(byte)0);
        setMaxPageIndex(0);
        setMaxDataIndex(0);
        currentPageIndex=0;
        activatePageIndex=0;
        this.start=start;
        if(start)
        {
            requestMaxPageIndex();
        }
    }

    @Override
    public void statusChange(StatusChangeEvent event)
    {
        if(event.getSource() instanceof Smctp&&event.getReason()==StatusChangeEvent.SMCTP_GET_NAME)
        {
            setSaveArgPrefix(((Smctp)event.getSource()).getCurrentConnect());
        }
        if(event.getReason()==StatusChangeEvent.START)
        {
            start=true;
        }
        if(event.getReason()==StatusChangeEvent.STOP)
        {
            start=false;
        }
        if(event.getReason()==StatusChangeEvent.START||event.getReason()==StatusChangeEvent.STOP)
        {
            clear();
        }
    }


    class FreshRunnable extends Thread
    {
        private void updateAndSleep() throws InterruptedException
        {
            for(int i=0;i<20;++i)
            {
                updateAndSleep(1);
            }
        }

        class NeedSendValueException extends RuntimeException
        {
        }

        private boolean sendingValue;

        private void updateAndSleep(long millis) throws InterruptedException
        {
            sleep(millis);
            if(!start)
            {
                throw new NotStartException();
            }
            if(!sendingValue)
            {
                for(MenuItemJPanel menuItem: menuItems)
                {
                    if((menuItem instanceof ExRequestValueInterface&&((ExRequestValueInterface)menuItem).needSendExValue())||menuItem instanceof SendableMenuItem&&((SendableMenuItem)menuItem).needSendValue())
                    {
                        throw new NeedSendValueException();
                    }
                }
            }
        }

        private void requestOther(int dataIndex) throws InterruptedException
        {
            if(menuItems[dataIndex]!=null)
            {
                if(menuItems[dataIndex].needRequest)
                {
                    requestData(dataIndex);
                    updateAndSleep();
                }
                if(menuItems[dataIndex] instanceof ExRequestDataInterface&&((ExRequestDataInterface)menuItems[dataIndex]).needExRequest())
                {
                    ((ExRequestDataInterface)menuItems[dataIndex]).exRequestData(this::updateAndSleep);
                }
                if(menuItems[dataIndex] instanceof ExRequestValueInterface)
                {
                    ((ExRequestValueInterface)menuItems[dataIndex]).requestExValue(this::updateAndSleep);
                }
                if(menuItems[dataIndex].needRequestValue&&menuItems[dataIndex] instanceof ValuableMenuItem)
                {
                    ((ValuableMenuItem)menuItems[dataIndex]).requestValue();
                    updateAndSleep();
                }
            }
        }

        @Override
        public void run()
        {
            while(true)
            {
                try
                {
                    if(start)
                    {
                        sendingValue=true;
                        updateAndSleep();
                        requestMaxPageIndex();
                        updateAndSleep(pageSelectJPanel.getComponentCount()==activePageCnt?500:10);
                        for(MenuItemJPanel menuItem: menuItems)
                        {
                            if(menuItem instanceof ExRequestValueInterface&&((ExRequestValueInterface)menuItem).needSendExValue())
                            {
                                ((ExRequestValueInterface)menuItem).sendExValueToDevice(this::updateAndSleep);
                            }
                            if(menuItem instanceof SendableMenuItem&&((SendableMenuItem)menuItem).needSendValue())
                            {
                                ((SendableMenuItem)menuItem).sendValueToDevice();
                                updateAndSleep();
                            }
                        }
                        sendingValue=false;
                        for(int pageIndex=0;pageIndex<pageSelectJPanel.getComponentCount()-activePageCnt;++pageIndex)
                        {
                            requestPageInfo(pageIndex);
                            updateAndSleep();
                        }
                        for(int dataIndex=0;dataIndex<menuItems.length;++dataIndex)
                        {
                            if(menuItems[dataIndex]==null)
                            {
                                requestData(dataIndex);
                                updateAndSleep();
                                for(int i=0;i<menuItems.length;++i)
                                {
                                    if(menuItems[i]!=null&&(((menuItems[i].page==currentPageIndex)||((currentPageIndex<0&&menuItems[i].isActivate())))))
                                    {
                                        requestOther(i);
                                    }
                                }
                            }
                            requestOther(dataIndex);
                        }
                        for(MenuItemJPanel menuItemJPanel: menuItems)
                        {
                            if(menuItemJPanel!=null)
                            {
                                menuItemJPanel.needRequestValue|=(menuItemJPanel.page==currentPageIndex)||((currentPageIndex<0&&menuItemJPanel.isActivate()));
                            }
                        }//更新menuItem要不要请求
                    }
                    else
                    {
                        sleep(100);
                    }
                }catch(NotStartException|NeedSendValueException ignore)
                {
                }catch(Exception ex)
                {
                    ex.printStackTrace();
                }
            }
        }
    }
}
